package com.skymxc.skin

import android.app.Activity
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import java.lang.Exception
import java.lang.reflect.Constructor
import java.util.*

/**
 * <p>
 *  用来接管系统的view的生产过程
 *  这里是模仿的 AppcompatLayoutFactory
 * </p>
 *
 * @author 孟祥超
 * <p>
 * date: 2021/9/20  10:47 下午
 */
class SkinLayoutInflaterFactory(
    // 用于获取窗口的状态框的信息
    private val activity: Activity

) : LayoutInflater.Factory2, Observer {

    private val TAG= "SkinInflaterFactory"
    private val mClassPrefixList = arrayOf(
        "android.widget.",
        "android.webkit.",
        "android.app.",
        "android.view."
    )

    //记录 View 对应的构造函数，是个两参的构造函数 context ，Attributes
    private val mConstructorSignature: Array<Class<*>> = arrayOf(
        Context::class.java, AttributeSet::class.java
    )

    //构造函数缓存，用于提升性能
    private val mConstructorMap = HashMap<String, Constructor<out View?>>()

    //页面属性管理器 当选择新皮肤后需要替换View与之对应的属性
    private val skinAttribute: SkinAttribute = SkinAttribute()
    override fun onCreateView(
        parent: View?,
        name: String,
        context: Context,
        attrs: AttributeSet
    ): View? {
        //换肤就是在需要时候替换 View的属性(src、background等)
        //所以这里创建 View,从而收集View属性
        var view = createSDKView(name, context, attrs)
        if (null == view) {
            view = createView(name, context, attrs)
        }
        //这就是我们加入的逻辑
        if (null != view) {
            //加载属性
            skinAttribute.look(view, attrs)
        }
        return view
    }
    private fun createSDKView(name: String, context: Context, attrs: AttributeSet): View? {
        //如果包含 . 则不是SDK中的view 可能是自定义view包括support库中的View
        if (-1 != name.indexOf('.')) {
            return null
        }
        //不包含就要在解析的 节点 name前，拼上： android.widget. 等尝试去反射
        for (i in mClassPrefixList.indices) {
            val view = createView(
                mClassPrefixList.get(i).toString() + name,
                context,
                attrs
            )
            if (view != null) {
                return view
            }
        }
        return null
    }

    private fun createView(name: String, context: Context, attrs: AttributeSet): View? {
        val constructor = findConstructor(context, name)
        try {
            return constructor!!.newInstance(context, attrs)
        } catch (e: Exception) {
        }
        return null
    }


    private fun findConstructor(context: Context, name: String): Constructor<out View>? {
        var constructor: Constructor<out View>? = mConstructorMap.get(name)
        if (constructor == null) {
            try {
                val clazz = context.classLoader.loadClass(name).asSubclass(
                    View::class.java
                )
                constructor = clazz.getConstructor(*mConstructorSignature)
               mConstructorMap.put(name, constructor)
            } catch (e: Exception) {
            }
        }
        return constructor
    }


    override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
        return null
    }

    override fun update(o: Observable?, arg: Any?) {
        Log.i(TAG, "update: $activity")
        updateStatusBarColor(activity)
        skinAttribute.applySkin()
    }
}